﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using IndexingHandler;
using System.Diagnostics;

namespace QueueIndexing
{
    public partial class MainForm : Form
    {
        public string[] args; // Аргументы командной строки

        // Библиотека обработки очереди на индексацию.
        // Т.к. индексатор в библиотеке ImportAPI запускается в отдельном потоке, то переменную приходится держать глобальной для мониторинга состояния индексации
        QueueHandler queueHandler;
        LogHandler logHandler;

        // Процедуры автоматизации процесса полуения данных из очереди и запуска индексации
        private void FillQueueList()
        {
            QueueHandler queueHandler = new QueueHandler { dbHandler = new DBHandler { ServerName = textBoxServer.Text, Database = textBoxBase.Text, UserName = textBoxUser.Text, Pwd = textBoxPassword.Text, DomainAuth = checkBoxDomainAuth.Checked, Schema = "dbo" }, logHandler = this.logHandler };
            DBHandler dbHandler = queueHandler.dbHandler;
            Cursor.Current = Cursors.WaitCursor;
            bool connResult = dbHandler.Connect();
            if (!connResult)
            {
                if (!AutoParamExists()) MessageBox.Show(dbHandler.connectException.Message, MainResource.DialogHeaderError, MessageBoxButtons.OK, MessageBoxIcon.Error);
                logHandler.WriteLogStr("FillQueueList " + dbHandler.connectException.Message);
            }
            else
            {
                ShowQueuelist(queueHandler, true);
                dbHandler.CloseConnection();
                Indexingbutton.Enabled = true;
                // Покажем информационное сообщение об удачности подключения
                if (!AutoParamExists()) MessageBox.Show(MainResource.MessageConnectionOK, MainResource.DialogHeaderInfo, MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            Cursor.Current = Cursors.Default;
        }

        private bool IndexingIsRunning(out string info)
        {
            Process[] processlist = Process.GetProcesses();

            info = "";
            foreach(Process theprocess in processlist)
            {
                //logHandler.WriteLogStr("Process: " + theprocess.ProcessName + " ID: " + theprocess.Id);
                info = "Process: " + theprocess.ProcessName + " ID: " + theprocess.Id;
                if (theprocess.ProcessName == "QueueIndexing" & theprocess.Id != Process.GetCurrentProcess().Id) return true;
            }
            return false;
        }
        
        private void IndexingQueue()
        {
            // Перед запуском проверим, нет ли в процессах запущенного индексатора
            // Если есть - запишем в лог и выйдем
            string info = "";
            if (IndexingIsRunning(out info))
            {
                logHandler.WriteLogStr("\t IndexingQueue - another one indexing process detected (" + info + ")");
                if (AutoParamExists()) this.Close();
                else 
                {
                    MessageBox.Show(MainResource.IndexingProcessDetected, MainResource.DialogHeaderError, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                };
            }
            queueHandler = new QueueHandler
            {
                dbHandler = new DBHandler { ServerName = textBoxServer.Text, Database = textBoxBase.Text, UserName = textBoxUser.Text, Pwd = textBoxPassword.Text, DomainAuth = checkBoxDomainAuth.Checked, Schema = "dbo" },
                configFile = textBoxPathToConfig.Text,
            };
            DBHandler dbHandler = queueHandler.dbHandler;
            Cursor.Current = Cursors.WaitCursor;
            bool connResult = dbHandler.Connect();
            if (!connResult)
            {
                if (!AutoParamExists()) MessageBox.Show(dbHandler.connectException.Message, MainResource.DialogHeaderError, MessageBoxButtons.OK, MessageBoxIcon.Error);
                logHandler.WriteLogStr("IndexingQueue " + dbHandler.connectException.Message);
                Cursor.Current = Cursors.Default;
                return;
            }
            // Получим список для индексации
            List<QueueStructure> IndexingQueue = GetSelectedQueueList();
            if (IndexingQueue.Count > 0)
            {
                toolStripStatusLabelIndexing.Text = MainResource.IndexingStatus;
                // Т.к. индексация идет в отдельном потоке, кнопки обновления сделаем недоступными
                SetControStatus(false);
                // Отправим список на индексацию
                queueHandler.IndexCatalogList(IndexingQueue);
                // Проверим вернувшийся идентификатор очереди
                if (queueHandler.importKey == 0)
                {
                    // Отметим в очереди ошибку постановки в очередь индексации
                    IndexingQueue = UpdateIndexingQueueStatus(IndexingQueue, QueueStatuses.Error, MainResource.ErrorIndexImport);
                    queueHandler.updateProcessingResult(IndexingQueue);
                    // Обновим список
                    ShowQueuelist(queueHandler, false);
                    // Вернем в исходное состояние контролы
                    SetControStatus(true);
                    // При автоматическом запуске закроем форму
                    if (AutoParamExists()) this.Close();
                }
                else
                {
                    // Запустим таймер мониторинга
                    Check_timer.Enabled = true;
                }
            }
            else
            {
                logHandler.WriteLogStr("IndexingQueue " + MainResource.MessageNoOneRecordSelected);
                if (!AutoParamExists()) MessageBox.Show(MainResource.MessageNoOneRecordSelected, MainResource.DialogHeaderError, MessageBoxButtons.OK, MessageBoxIcon.Error);
                else this.Close();
                Cursor.Current = Cursors.Default;
                queueHandler = null;
            }
            Cursor.Current = Cursors.Default;
            // Закроем подключение к базе
            dbHandler.CloseConnection();
        }
        
        public MainForm()
        {
            InitializeComponent();
            initQueuelistView();
        }
        
        private void OK_button_Click(object sender, EventArgs e)
        {
            logHandler.fileName = textBoxPathToLog.Text;
            QueueHandler queueHandler = new QueueHandler 
            { dbHandler = new DBHandler { ServerName = textBoxServer.Text, Database = textBoxBase.Text, UserName = textBoxUser.Text, Pwd = textBoxPassword.Text, DomainAuth = checkBoxDomainAuth.Checked, Schema = "dbo" },
              configFile = textBoxPathToConfig.Text,
              logHandler = this.logHandler
            };
            ServiceProcs.SaveParamsToXml(queueHandler);
            Close();
        }

        // Процедура инициализации QueuelistView
        private void initQueuelistView()
        {
            QueuelistView.Columns.Add(MainResource.ColumnStatus, 50, HorizontalAlignment.Center);
            QueuelistView.Columns.Add(MainResource.ColumnInsertDate, -2, HorizontalAlignment.Center);
            QueuelistView.Columns.Add(MainResource.ColumnKey, -2, HorizontalAlignment.Right);
            QueuelistView.Columns.Add(MainResource.ColumnId, -2, HorizontalAlignment.Left);
            QueuelistView.Columns.Add(MainResource.ColumnLastIndexingDate, -2, HorizontalAlignment.Center);
            QueuelistView.Columns.Add(MainResource.ColumnErrInfo, -2, HorizontalAlignment.Left);
            QueuelistView.CheckBoxes = true;
            QueuelistView.View = View.Details;
            QueuelistView.GridLines = true;
            QueuelistView.FullRowSelect = true;
        }
        
        // Процедура отображения на форме записей для индексации
        private void ShowQueuelist(QueueHandler queueHandler, bool NeedToLog)
        {
            // Получим активную очередь индексатора
            List<QueueStructure> IndexingQueue = queueHandler.GetIndexingQueue(NeedToLog);
            // Отобразим ее на форме
            QueuelistView.Items.Clear();
            foreach (QueueStructure queueRecord in IndexingQueue)
            {
                //index = checkedListBoxQueue.Items.Add(queueRecord, true);
                var newItem = new ListViewItem();
                newItem.SubItems.Add(queueRecord.INSERT_DATE.ToString());
                newItem.SubItems.Add(queueRecord.PORTALKEY.ToString());
                newItem.SubItems.Add(queueRecord.OBJECT_ID.ToString());
                newItem.SubItems.Add(queueRecord.END_INDEXING_DATE.ToString());
                newItem.SubItems.Add(queueRecord.LOAD_ERROR_INFO.ToString());
                newItem.ImageIndex = (int)queueRecord.STATUS_ID - 1;
                newItem.Tag = queueRecord;
                QueuelistView.Items.Add(newItem);
            }
            // Подгоним ширину колонок 
            QueuelistView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
        }
        
        private void Check_button_Click(object sender, EventArgs e)
        {
            FillQueueList();
        }

        private void checkBoxDomainAuth_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxDomainAuth.Checked)
            {
                textBoxUser.Text = "";
                textBoxPassword.Text = "";
            }
            textBoxUser.Enabled = !checkBoxDomainAuth.Checked;
            textBoxPassword.Enabled = !checkBoxDomainAuth.Checked;
        }

        // Процедура инициализации парамеетров подключения
        private void LoadParams()
        {
            QueueHandler queueHandler = ServiceProcs.LoadParamsFromXml();
            DBHandler dbHandler = queueHandler.dbHandler;
            if (dbHandler == null) return;
            textBoxServer.Text = dbHandler.ServerName;
            textBoxBase.Text = dbHandler.Database;
            textBoxUser.Text = dbHandler.UserName;
            textBoxPassword.Text = dbHandler.Pwd;
            checkBoxDomainAuth.Checked = dbHandler.DomainAuth;
            textBoxPathToConfig.Text = queueHandler.configFile;
            textBoxPathToLog.Text = queueHandler.logHandler.fileName;
            // После загрузки параметров проверим необходимости провести ротацию логов
            string logFile = textBoxPathToLog.Text;
            // (Заархивировать текущий лог и создать новый)
            if (logFile != "")
            {
                ZipHandler zipHandler = new ZipHandler(logFile);
                zipHandler.maxFileLength = 1024 * 1024; // Размер файла, при котором проводим ротацию лога (1Мб)
                zipHandler.RotateLogs();
            }
            // Инициализируем логер
            if (logFile != "") logHandler = new LogHandler(logFile);
            else logHandler = new LogHandler();
        }

        private bool AutoParamExists()
        {
            var match = args.FirstOrDefault(stringToCheck => args.Contains("auto"));
            if (match == null) return false;
            else return true;
        }
        
        private void MainForm_Load(object sender, EventArgs e)
        {
            LoadParams();
            Indexingbutton.Enabled = false;
            logHandler.WriteMessage("==================================");
            logHandler.WriteLogStr("Program has started (MainForm_Load) args = " + string.Join(" ", args.ToArray()));
            // Если в параметрах запуска передали "auto", то:
            if (AutoParamExists())
            {
                // 1. Получим очередь для индексации
                FillQueueList();
                // 2. Отметим все строки
                HandleList(SelectTypes.SelectAll);
                // 3. Запустим индексацию
                IndexingQueue();
                // 4. По выполнению закроем форму
            }
        }

        private void Cancel_button_Click(object sender, EventArgs e)
        {
            Close();
        }

        // Функция возвращает список отмеченных на форме записей для индексации
        private List<QueueStructure> GetSelectedQueueList()
        {
            List<QueueStructure> IndexingQueue = new List<QueueStructure>();
            foreach (ListViewItem item in QueuelistView.Items)
            {
                if (item.Checked)
                {
                    item.ImageIndex = (int)QueueStatuses.Processing - 1;
                    // Добавим запись в список на индексацию
                    IndexingQueue.Add(item.Tag as QueueStructure);
                }
            }
            return IndexingQueue;
        }
        
        private void Indexing_button_Click(object sender, EventArgs e)
        {
            IndexingQueue();
        }

        private void buttonOpenConfigFile_Click(object sender, EventArgs e)
        {
            DialogResult result = openFileDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                textBoxPathToConfig.Text = openFileDialog1.FileName;
            }
        }

        private void Check_timer_Tick(object sender, EventArgs e)
        {
            // Проверим состояние индексатора и отобразим информацию на форме
            IndexingStatus status = queueHandler.GetQueueStatus();
            if (status.Status != QueueStatuses.Processing)
            {
                toolStripStatusLabelIndexing.Text = "";
                DBHandler dbHandler = queueHandler.dbHandler;
                Cursor.Current = Cursors.WaitCursor;
                bool connResult = dbHandler.Connect();
                if (!connResult)
                {
                    Check_timer.Enabled = false;
                    Cursor.Current = Cursors.Default;
                    if (!AutoParamExists()) MessageBox.Show(dbHandler.connectException.Message, MainResource.DialogHeaderError, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                Check_timer.Enabled = false;
                // Получим список для индексации
                List<QueueStructure> IndexingQueue = GetSelectedQueueList();
                // Расставим в нем вернувшиеся статусы индексации
                IndexingQueue = UpdateIndexingQueueStatus(IndexingQueue, status);
                // Отметим это в очереди
                if (queueHandler.logHandler == null) queueHandler.logHandler = logHandler;
                queueHandler.updateProcessingResult(IndexingQueue);
                SetControStatus(true);
                Cursor.Current = Cursors.Default;
                if (!AutoParamExists()) MessageBox.Show(MainResource.MessageIndexingHasFinished, MainResource.DialogHeaderInfo, MessageBoxButtons.OK, MessageBoxIcon.Information);
                // Обновим список на форме
                ShowQueuelist(queueHandler, false);
                // При автоматическом запуске закроем форму
                if (AutoParamExists()) this.Close();
            }
        }

        // Функция возвращает обновленный статус очереди
        private List<QueueStructure> UpdateIndexingQueueStatus(List<QueueStructure> in_IndexingQueue, IndexingStatus status)
        {
            List<QueueStructure> IndexingQueue = in_IndexingQueue;
            // Если индексация слетает по недоступности сервера, то библиотека ImportAPI возвращает пустой список детализации и статус "Завершено".
            // Exceptions проглатываются внутри и пишутся в лог.
            // Таким образом, если вернулся пустой список при непустом исходном списке, то для всех записей запишем ошибку "Unknown error"
            if (in_IndexingQueue.Count > 0 & status.DetailList.Count == 0)
            {
                foreach (QueueStructure IndexingRecord in IndexingQueue)
                {
                    IndexingRecord.STATUS_ID = QueueStatuses.Error;
                    IndexingRecord.LOAD_ERROR_INFO = MainResource.LoadErrorUnknown;
                }
            }
            else
            {
                foreach (QueueStructure IndexingRecord in IndexingQueue)
                {
                    List<ImportRecordDetails> DetailList = status.DetailList;
                    foreach (ImportRecordDetails item in DetailList)
                    {
                        if ((string)IndexingRecord.OBJECT_ID == item.ID_DataSource)
                        {
                            IndexingRecord.STATUS_ID = item.Status;
                            IndexingRecord.LOAD_ERROR_INFO = item.ErrorLog;
                            IndexingRecord.START_INDEXING_DATE = item.DateStart;
                            IndexingRecord.END_INDEXING_DATE = item.DateEnd;
                        }
                    }
                }
            }
            return IndexingQueue;
        }
        
        private List<QueueStructure> UpdateIndexingQueueStatus(List<QueueStructure> in_IndexingQueue, QueueStatuses queueStatus, string Erro_Info)
        {
            List<QueueStructure> IndexingQueue = in_IndexingQueue;
            foreach (QueueStructure IndexingRecord in IndexingQueue)
            {
                IndexingRecord.STATUS_ID = queueStatus;
                IndexingRecord.LOAD_ERROR_INFO = Erro_Info;
            }
            return IndexingQueue;
        }

        private void SetControStatus(bool Status)
        {
            Indexingbutton.Enabled = Status;
            Check_button.Enabled = Status;
            OK_button.Enabled = Status;
            Cancel_button.Enabled = Status;
            if (Status)
            {
                toolStripStatusLabelIndexing.Text = "";
            }
            /*
            SelectAll_button.Enabled = Status;
            InvertSelection_button.Enabled = Status;
            UnselectAll_button.Enabled = Status;
            //QueuelistView.Enabled = Status;
             * */
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (queueHandler == null) return;
            IndexingStatus status = queueHandler.GetQueueStatus();
            // Если процесс индексации не завершился - спросим о закрытии формы 
            if (status.Status == QueueStatuses.Processing)
            {
                if (!AutoParamExists())
                {
                    DialogResult result = MessageBox.Show(MainResource.MessageCloseQuestion, MainResource.DialogHeaderQuestion, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if (result != DialogResult.Yes)
                    {
                        e.Cancel = true;
                    }
                }
            }
        }

        // Процедура отметки списка
        private void HandleList(SelectTypes selectType)
        {
            foreach (ListViewItem item in QueuelistView.Items)
            {
                if (selectType == SelectTypes.SelectAll) { item.Checked = true; }
                if (selectType == SelectTypes.UnselectAll) { item.Checked = false; }
                if (selectType == SelectTypes.InvertSelection) { item.Checked = !item.Checked; }
            }
        }

        private void SelectAll_button_Click(object sender, EventArgs e)
        {
            HandleList(SelectTypes.SelectAll);
        }

        private void InvertSelection_button_Click(object sender, EventArgs e)
        {
            HandleList(SelectTypes.InvertSelection);
        }

        private void UnselectAll_button_Click(object sender, EventArgs e)
        {
            HandleList(SelectTypes.UnselectAll);
        }

        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            logHandler.WriteLogStr("Program has closed (MainForm_FormClosed): CloseReason = " + e.CloseReason);
        }

        private void buttonOpenLogFile_Click(object sender, EventArgs e)
        {
            DialogResult result = saveFileDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                textBoxPathToLog.Text = saveFileDialog1.FileName;
            }
        }
    }

    enum SelectTypes
    {
        SelectAll,
        UnselectAll,
        InvertSelection
    }
}
